home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / c / bisonpcb.zip / HOC6.Y < prev    next >
Text File  |  1987-09-21  |  8KB  |  312 lines

  1. /* 
  2.  *  hoc6 from 'The UNIX PROGRAM ENVIRONMENT' 
  3.  *    by Brian W. Kernighan and Rob Pike
  4.  */
  5. %{
  6. #include "hoc.h"
  7. #define code2(c1,c2) code(c1);code(c2)
  8. #define code3(c1,c2,c3) code(c1);code(c2);code(c3)
  9. int indef;
  10. %}
  11. %union {
  12.       Symbol *sym;        /* symbol table pointer */
  13.       Inst *inst;           /* machine instructions */
  14.       int narg;         /* number of arguments */
  15. }
  16.  
  17. %start list
  18.  
  19. %token <sym> NUMBER STRING PRINT VAR BLTIN UNDEF WHILE IF ELSE
  20. %token <sym> FUNCTION PROCEDURE RETURN FUNC PROC READ
  21. %token <narg> ARG
  22. %type <inst> stmt asgn expr stmtlist cond while if end prlist begin
  23. %type <sym> procname
  24. %type <narg> arglist
  25. %right '='
  26. %left OR
  27. %left AND
  28. %left GT GE LT LE EQ NE
  29. %left '+' '-'
  30. %left '*' '/' 
  31. %left UNARYMINUS NOT
  32. %right '^'
  33.  
  34. %%
  35.  
  36. list: /* empty */
  37.     | list '\n'
  38.    | list defn '\n'
  39.    | list asgn '\n' {code2(pop,STOP); return 1;} 
  40.    | list stmt '\n' {code(STOP); return 1;}
  41.    | list expr '\n' {code2(print, STOP); return 1;}
  42.     | list error '\n'    {yyerror("at list\n");}
  43.     ;
  44. asgn: VAR '=' expr   { code3(varpush,(Inst)$1,assign);$$=$3;}
  45.    | ARG '=' expr {defnonly("$"); code2(argassign,(Inst)$1); $$=$3;}
  46.     ;
  47. stmt: expr  {code(pop);}
  48.    | RETURN {defnonly("return"); code(procret);}
  49.    | RETURN expr  {defnonly("return"); $$ = $2; code(funcret); }
  50.    | PROCEDURE begin '(' arglist ')'   {$$ = $2; code3(call, (Inst)$1, (Inst)$4); }
  51.    | PRINT prlist   {$$ = $2;}
  52.    | while cond stmt end{
  53.       ($1)[1] = (Inst)$3;  /* body of loop */
  54.       ($1)[2] = (Inst)$4; }  /* end, if cond fails */
  55.    | if cond stmt end{  /* else-less if */
  56.       ($1)[1] = (Inst)$3;  /* thenpart */
  57.       ($1)[3] = (Inst)$4;  } /* end, if cond fails */
  58.    | if cond stmt end ELSE stmt end {  /* if with else */
  59.       ($1)[1] = (Inst)$3; /* thenpart */
  60.       ($1)[2] = (Inst)$6;  /* elsepart */
  61.       ($1)[3] = (Inst)$7; } /*end, if cond fails */
  62.    | '{' stmtlist '}'      {$$ = $2; }
  63.    ;
  64. cond: '(' expr ')' {code(STOP); $$ = $2;}
  65.    ;
  66. while:   WHILE { $$ = code3(whilecode, STOP, STOP);}
  67.    ;
  68. if:   IF { $$ = code(ifcode); code3(STOP, STOP, STOP); }
  69.    ;
  70. begin:   /* nothing */     { $$ = progp; }
  71.    ;
  72. end:  /* nothing */  { code(STOP); $$ = progp;}
  73.    ;
  74. stmtlist:   /* nothing */  { $$ = progp;}
  75.    | stmtlist '\n'
  76.    | stmtlist stmt
  77.    ;
  78. expr:  NUMBER  {$$ = code2(constpush, (Inst)$1);}
  79.    | VAR       {$$ = code3(varpush, (Inst)$1, eval);}
  80.    | ARG {defnonly("$"); $$ = code2(arg, (Inst)$1); }
  81.    | asgn
  82.    | FUNCTION begin '(' arglist ')' {$$ = $2; code3(call,(Inst)$1,(Inst)$4); }
  83.    | READ '(' VAR ')'   {$$ = code2(varread, (Inst)$3);}
  84.    | BLTIN '(' expr ')' {$$ = $3; code2(bltin, (Inst)$1->u.ptr);}
  85.    | '(' expr ')'  { $$ = $2;}
  86.     | expr '+' expr      {code(add);}
  87.     | expr '-' expr      {code(sub);}
  88.     | expr '*' expr      {code(mul);}
  89.     | expr '/' expr      {code(div);}
  90.    | expr '^' expr      {code(power);}
  91.    | '-' expr %prec UNARYMINUS   { $$=$2; code(negate);}
  92.    | expr GT expr {code(gt);}
  93.    | expr GE expr {code(ge);}
  94.    | expr LT expr {code(lt);}
  95.    | expr LE expr {code(le);}
  96.    | expr EQ expr {code(eq);}
  97.    | expr NE expr {code(ne);}
  98.    | expr AND expr {code(and);}
  99.    | expr OR expr {code(or);}
  100.    | NOT expr  {$$ = $2; code(not); }
  101.     ;
  102. prlist: expr      {code(prexpr);}
  103.    | STRING        {$$ = code2(prstr, (Inst)$1);}
  104.    | prlist ',' expr    {code(prexpr);}
  105.    | prlist ',' STRING  {code2(prstr, (Inst)$3);}
  106.    ;      
  107. defn: FUNC procname { $2->type=FUNCTION; indef=1;}
  108.       '(' ')' stmt   {code(procret); define($2); indef=0;}
  109.    | PROC procname { $2->type=PROCEDURE; indef=1; }
  110.       '(' ')' stmt {code(procret); define($2); indef=0; }
  111.    ;
  112. procname:   VAR
  113.    | FUNCTION
  114.    | PROCEDURE
  115.    ;
  116. arglist: /* nothing */        { $$ = 0; }
  117.    | expr                     { $$ = 1; }
  118.    | arglist ',' expr         { $$ = $1 + 1; }
  119.    ;
  120.  
  121. %%
  122. #include <ctype.h>
  123. #include <signal.h>
  124. #include <setjmp.h>
  125. char *progname;
  126. int lineno = 1;
  127. char *infile;     /* input file name */
  128. FILE *fin;        /* input file pointer */
  129. char **gargv;     /* global argument list */
  130. int gargc;
  131. int c;   /* global for use by warning() */
  132.  
  133. jmp_buf begin;
  134.  
  135. yylex()
  136. {
  137.    while ((c=getc(fin)) == ' ' || c == '\t')
  138.          ;
  139.    if (c == EOF)
  140.       return 0;
  141.    if (c == '.' || isdigit(c)){ /* number */
  142.       double d;
  143.       ungetc (c,fin);
  144.       fscanf(fin, "%lf", &d);
  145.       yylval.sym = install("",NUMBER,d);
  146.       return NUMBER;
  147.    }
  148.    if (isalpha(c)){
  149.       Symbol *s;
  150.       char sbuf[100], *p=sbuf;
  151.       do{
  152.          if (p >= sbuf + sizeof(sbuf) -1){
  153.             *p = '\0';
  154.             execerror("name too long", sbuf);
  155.          }
  156.          *p++ = c;
  157.       }while ((c=getc(fin)) != EOF && isalnum(c));
  158.       ungetc(c,fin);
  159.       *p = '\0';
  160.       if ((s=lookup(sbuf)) == 0)
  161.          s= install(sbuf, UNDEF, 0.0);
  162.       yylval.sym = s;
  163.       return s->type == UNDEF ? VAR : s->type;
  164.    }      
  165.    if (c == '$'){ /* argument? */
  166.       int n = 0;
  167.       while (isdigit(c=getc(fin)))
  168.          n = 10 * n + c - '0';
  169.       ungetc(c,fin);
  170.       if (n ==0 )
  171.          execerror("strange $...", (char *) 0);
  172.       yylval.narg = n;
  173.       return ARG;
  174.    }
  175.    if (c == '"'){ /* quoted string */
  176.       char sbuf[100], *p, *emalloc();
  177.       for (p=sbuf; (c=getc(fin)) != '"'; p++){
  178.          if (c == '\n' || c == EOF)
  179.             execerror("missing quote", "");
  180.          if (p >= sbuf + sizeof(sbuf) -1){
  181.             *p = '\0';
  182.             execerror("string too long", sbuf);
  183.          }
  184.          *p = backslash(c);
  185.       }
  186.       *p = 0;
  187.       yylval.sym = (Symbol *)emalloc(strlen(sbuf)+1);
  188.       strcpy(yylval.sym, sbuf);
  189.       return STRING;
  190.    }
  191.    switch(c){
  192.       case '>':   return follow('=',GE,GT);
  193.       case '<':   return follow('=',LE,LT);
  194.       case '=':   return follow('=',EQ,'=');
  195.       case '!':   return follow('=',NE,NOT);
  196.       case '|':   return follow('|',OR,'|');
  197.       case '&':   return follow('&',AND,'&');
  198.       case '\n':  lineno++; return '\n';
  199.       default:    return c;
  200.    }
  201. }
  202.  
  203. backslash(c)      /* get next char with \'s interpreted */
  204. int c;
  205. {
  206.    char *strchr();   /* index() in some systems */
  207.    static char transtab[] = "b\bf\fn\nr\rt\t";
  208.    if (c != '\\')
  209.       return c;
  210.    c = getc(fin);
  211.    if (islower(c) && strchr(transtab,c))
  212.       return strchr(transtab,c)[1];
  213.    return c;
  214. }
  215.  
  216. follow(expect, ifyes, ifno)
  217. int expect,ifyes,ifno;
  218. {
  219.    int c= getc(fin);
  220.  
  221.    if (c == expect)
  222.       return ifyes;
  223.    ungetc(c, fin);
  224.    return ifno;
  225. }
  226.  
  227.  
  228. defnonly(s) /* warn if illegal definition */
  229. char *s;
  230. {
  231.    if (!indef)
  232.       execerror(s, "used outside definition");
  233. }
  234.  
  235. void
  236. yyerror(s)
  237. char *s;
  238. {
  239.    puts(s);
  240.    exit(1);
  241. }
  242.  
  243. execerror(str,str1)
  244. char * str, * str1;
  245. {
  246.    warning(str,str1);
  247.    fseek(fin,0L,2);  /* flush rest of file */
  248.    longjmp(begin,0);
  249. }
  250.  
  251.  
  252. main(argc,argv)
  253. char *argv[];
  254. {
  255.    int i;
  256.    progname = argv[0];
  257.    if (argc == 1){   /* fake an argument list */
  258.       static char *stdinonly[] = {"-"};
  259.       gargv = stdinonly;
  260.       gargc = 1;
  261.    } else {
  262.       gargv = argv+1;
  263.       gargc = argc - 1;
  264.    }
  265.    init();
  266.    while (moreinput())
  267.       run();
  268.    return 0;
  269. }
  270.  
  271. moreinput()
  272. {
  273.    if (gargc-- <=0)
  274.       return 0;
  275.    if (fin && fin != stdin)
  276.       fclose(fin);
  277.    infile = *gargv++;
  278.    lineno = 1;
  279.    if (strcmp(infile, "-") == 0){
  280.       fin = stdin;
  281.       infile = 0;
  282.    }
  283.    else if ((fin=fopen(infile,"r")) == NULL){
  284.       fprintf(stderr, "cant't open %s\n",infile);
  285.       return moreinput();
  286.    }
  287.    return 1;
  288. }
  289.  
  290. run() /* execute until EOF */
  291. {
  292.    setjmp(begin);
  293.    for (initcode(); yyparse();initcode())
  294.       execute(progbase);
  295. }
  296.  
  297. warning(s,t)
  298. char *s, *t;
  299. {
  300.    fprintf(stderr,"%s: %s",progname, s);
  301.    if (t)
  302.       fprintf(stderr, " %s",t);
  303.    if (infile)
  304.          fprintf(stderr," in %s", infile);
  305.    fprintf(stderr, " near line %d\n", lineno);
  306.    while (c != '\n' && c != EOF)
  307.       c = getc(fin); /* flush rest of input line */
  308.    if (c == '\n')
  309.       lineno++;
  310. }
  311.  
  312.